int write_file(int file, char* buf, uint nBytes)
{	
	int bytesWritten = 0;
	ulong numSingleIndirect = 0, numDoubleIndirect = 0, numTripleIndirect = 0;
	char* bufPnt = buf;
	OFT* fileEntry = runningProc->files[file];
	EXT2_DISK* diskInfo;
	SUPER super;
	
	if (fileEntry == 0)
	{
		printf("File doesn't exist!\n");
		return -1;
	}
	
	if (fileEntry->mode != FILE_READ)
	{
		if (get_device_info(fileEntry->memInode->location.deviceHandle, &diskInfo) == -1)
			return -1;
			
		if (get_super(fileEntry->memInode->location.deviceHandle, &super) == -1)
			return -1;
			
		/* Make sure under 8KB to write*/
		if (nBytes > MAX_BLOCK_SIZE)
			nBytes = MAX_BLOCK_SIZE;
			
		numSingleIndirect = diskInfo->blockSize / sizeof(ulong);
		numDoubleIndirect = numSingleIndirect * numSingleIndirect;
		numTripleIndirect = numDoubleIndirect * numSingleIndirect;
		
		while (bytesWritten < nBytes)
		{
			int fileBlockOffset = fileEntry->offset / diskInfo->blockSize;
			int blockWriteOffset = fileEntry->offset % diskInfo->blockSize;
			int bytesToWrite = 0;
			int fileGroup = (fileEntry->memInode->location.inodeNum - 1) / super.s_inodes_per_group;
			ulong blockToWrite = 0;
			char block[MAX_BLOCK_SIZE], *blockPnt = 0;
			
			/* Read direct block */
			if (fileBlockOffset < NUM_DIRECT_BLOCKS)
			{
				/* Check if block needs to be allocated */
				if (fileEntry->memInode->inode.i_block[fileBlockOffset] == 0)
				{
					fileEntry->memInode->inode.i_block[fileBlockOffset] =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if (fileEntry->memInode->inode.i_block[fileBlockOffset] == 0)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 fileEntry->memInode->inode.i_block[fileBlockOffset],
							 diskInfo->blockSize, block) == -1)
					return -1;
					
				blockToWrite = fileEntry->memInode->inode.i_block[fileBlockOffset];
			}
			
			/* Single indirect blocks */
			else if (fileBlockOffset < (NUM_DIRECT_BLOCKS + numSingleIndirect))
			{
				ulong singleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				int singleBlockOffset = fileBlockOffset - NUM_DIRECT_BLOCKS;
				
				/* Check if block needs to be allocated */
				if (fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS] == 0)
				{
					fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS] =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if (fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS] == 0)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS],
							 diskInfo->blockSize, (char*)singleIndirectBlock) == -1)
					return -1;
				
				/* Check if indirect block needs to be allocated */
				if ((*(ulong*)(singleIndirectBlock + singleBlockOffset)) == 0)
				{
					(*(ulong*)(singleIndirectBlock + singleBlockOffset)) =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if ((*(ulong*)(singleIndirectBlock + singleBlockOffset)) == 0)
						return -1;
					if (write_blk(fileEntry->memInode->location.deviceHandle,
							 	 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS],
							 	 diskInfo->blockSize, (char*)(singleIndirectBlock)) == -1)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(singleIndirectBlock + singleBlockOffset)),
							 diskInfo->blockSize, block) == -1)
					return -1;
					
				blockToWrite = (*(ulong*)(singleIndirectBlock + singleBlockOffset));
			}
			
			/* Double indirect blocks */
			else if (fileBlockOffset < (NUM_DIRECT_BLOCKS + numDoubleIndirect + numSingleIndirect))
			{
				ulong singleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				ulong doubleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				int singleBlockOffset = (fileBlockOffset - NUM_DIRECT_BLOCKS) / (numSingleIndirect) - 1;
				int doubleBlockOffset = (fileBlockOffset - NUM_DIRECT_BLOCKS) % (numSingleIndirect);
				
				/* Check if block needs to be allocated */
				if (fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS + 1] == 0)
				{
					fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS + 1] =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if (fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS + 1] == 0)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS + 1],
							 diskInfo->blockSize, (char*)singleIndirectBlock) == -1)
					return -1;
				
				/* Check if indirect block needs to be allocated */
				if ((*(ulong*)(singleIndirectBlock + singleBlockOffset)) == 0)
				{
					(*(ulong*)(singleIndirectBlock + singleBlockOffset)) =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if ((*(ulong*)(singleIndirectBlock + singleBlockOffset)) == 0)
						return -1;
					if (write_blk(fileEntry->memInode->location.deviceHandle,
							 	 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS + 1],
							 	 diskInfo->blockSize, (char*)(singleIndirectBlock)) == -1)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(singleIndirectBlock + singleBlockOffset)),
							 diskInfo->blockSize, (char*)(doubleIndirectBlock)) == -1)
					return -1;
					
				/* Check if double indirect block needs to be allocated */
				if ((*(ulong*)(doubleIndirectBlock + doubleBlockOffset) == 0))
				{
					(*(ulong*)(doubleIndirectBlock + doubleBlockOffset)) =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if ((*(ulong*)(doubleIndirectBlock + doubleBlockOffset)) == 0)
						return -1;
					if (write_blk(fileEntry->memInode->location.deviceHandle,
							 	 (*(ulong*)(singleIndirectBlock + singleBlockOffset)),
							 	 diskInfo->blockSize, (char*)(doubleIndirectBlock)) == -1)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(doubleIndirectBlock + doubleBlockOffset)),
							 diskInfo->blockSize, block) == -1)
					return -1;
					
				blockToWrite = (*(ulong*)(doubleIndirectBlock + doubleBlockOffset));
			}
			
			/* Triple indirect blocks */
			else if (fileBlockOffset < (NUM_DIRECT_BLOCKS + numTripleIndirect + numDoubleIndirect + numSingleIndirect))
			{
				ulong singleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				ulong doubleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				ulong tripleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				int singleBlockOffset = (fileBlockOffset - NUM_DIRECT_BLOCKS) / numSingleIndirect - 1;			
				int doubleBlockOffset = (fileBlockOffset - NUM_DIRECT_BLOCKS) / numDoubleIndirect - 1;
				int tripleBlockOffset = (fileBlockOffset - NUM_DIRECT_BLOCKS) % (numDoubleIndirect);
				
				/* Check if block needs to be allocated */
				if (fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS] == 0)
				{
					fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS] =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if (fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS] == 0)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS],
							 diskInfo->blockSize, (char*)singleIndirectBlock) == -1)
					return -1;
				
				/* Check if indirect block needs to be allocated */
				if ((*(ulong*)(singleIndirectBlock + singleBlockOffset)) == 0)
				{
					(*(ulong*)(singleIndirectBlock + singleBlockOffset)) =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if ((*(ulong*)(singleIndirectBlock + singleBlockOffset)) == 0)
						return -1;
					if (write_blk(fileEntry->memInode->location.deviceHandle,
							 	 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS],
							 	 diskInfo->blockSize, (char*)(singleIndirectBlock)) == -1)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(singleIndirectBlock + singleBlockOffset)),
							 diskInfo->blockSize, (char*)(doubleIndirectBlock)) == -1)
					return -1;
				
				/* Check if double indirect block needs to be allocated */
				if ((*(ulong*)(doubleIndirectBlock + doubleBlockOffset) == 0))
				{
					(*(ulong*)(doubleIndirectBlock + doubleBlockOffset)) =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if ((*(ulong*)(doubleIndirectBlock + doubleBlockOffset)) == 0)
						return -1;
					if (write_blk(fileEntry->memInode->location.deviceHandle,
							 	 (*(ulong*)(singleIndirectBlock + singleBlockOffset)),
							 	 diskInfo->blockSize, (char*)(doubleIndirectBlock)) == -1)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(doubleIndirectBlock + doubleBlockOffset)),
							 diskInfo->blockSize, (char*)tripleIndirectBlock) == -1)
					return -1;
					
				/* Check if triple indirect block needs to be allocated */
				if ((*(ulong*)(tripleIndirectBlock + tripleBlockOffset) == 0))
				{
					(*(ulong*)(tripleIndirectBlock + tripleBlockOffset)) =
						allocate_free_block(fileEntry->memInode->location.deviceHandle, fileGroup);
					if ((*(ulong*)(tripleIndirectBlock + tripleBlockOffset)) == 0)
						return -1;
					if (write_blk(fileEntry->memInode->location.deviceHandle,
							 	 (*(ulong*)(doubleIndirectBlock + doubleBlockOffset)),
							 	 diskInfo->blockSize, (char*)(tripleIndirectBlock)) == -1)
						return -1;
				}
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(tripleIndirectBlock + tripleBlockOffset)),
							 diskInfo->blockSize, block) == -1)
					return -1;
					
				blockToWrite = (*(ulong*)(tripleIndirectBlock + tripleBlockOffset));
			}
			
			/* Calculate bytes to read from block */
			if ((nBytes - bytesWritten) >= (diskInfo->blockSize - blockWriteOffset))
				bytesToWrite = diskInfo->blockSize - blockWriteOffset;
			else
				bytesToWrite = nBytes - bytesWritten;
				
			/* Update file size if necessary */
			if ((fileEntry->memInode->inode.i_size - fileEntry->offset) < bytesToWrite)
			{
				fileEntry->memInode->inode.i_size +=
					(bytesToWrite - (fileEntry->memInode->inode.i_size - fileEntry->offset));
				fileEntry->memInode->inode.i_blocks +=
					(((bytesToWrite - (fileEntry->memInode->inode.i_size - fileEntry->offset)) / SECTOR_SIZE) + 1);
			}
			
			/* Set block pointer and copy data */
			blockPnt = block + blockWriteOffset;		
			memcpy(blockPnt, bufPnt, bytesToWrite);
			
			/* Write data back to block */
			if (write_blk(fileEntry->memInode->location.deviceHandle,
						  blockToWrite, diskInfo->blockSize, block) == -1)
					return -1;
			
			/* Increment/Decrement counters */
			bufPnt += bytesToWrite;
			bytesWritten += bytesToWrite;
			fileEntry->offset += bytesToWrite;
		}
		return bytesWritten;
	}
	printf("File not opened for WRITE mode!\n");
	return -1;
}

int do_write(char* notUsed)
{
	int bytesToWrite = 0, fd = 0;
	int bytesWritten = 0, i = 0;
	char buf[MAX_BLOCK_SIZE];
	
	printf("Enter FD to write to: ");
	scanf("%d", &fd);
	
	if (runningProc->files[fd]->memInode != 0)
	{
		if (runningProc->files[fd]->mode == FILE_READ)
		{
			printf("FD %d is not open for write mode!\n\n", fd);
			return -1;
		}
		else
		{
			printf("Enter text to write to file:\n\n");
			getchar();
			gets(buf);
			return write_file(fd, buf, strlen(buf));			
		}
	}
	return -1;
}
